package com.cmic.rcs.emoji.interceptor;

import com.cmic.origin.login.grpc.LoginServiceGrpc;
import com.cmic.origin.login.grpc.LoginServiceOuterClass;
import com.cmic.rcs.emoji.common.CustomContext;
import com.cmic.rcs.emoji.common.UserContext;
import com.cmic.rcs.emoji.entity.dto.UserDto;
import com.cmic.rcs.emoji.util.CommonUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import static com.cmic.rcs.emoji.common.CustomContext.TRACE_ID;


@Slf4j
@Component
public class TokenInterceptor implements HandlerInterceptor {


    @Value("${spring.profiles.active}")
    private String active; // 开发环境、测试环境、生产环境

    @Autowired
    private LoginServiceGrpc.LoginServiceBlockingStub loginServiceGrpc;


    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
        // 设置traceId 作用是记录日志
        String traceId = StringUtils.defaultIfEmpty(request.getHeader(TRACE_ID), CommonUtils.getUuid());
        CustomContext.setTraceId(traceId);

         // 获取token
        String authorization = request.getHeader("Authorization");
        //拦截路径
        String requestURI = request.getRequestURI();
        log.info("TokenInterceptor拦截请求: {}", requestURI);
        if (ObjectUtils.isEmpty(authorization) || authorization.length() < 8 || !authorization.startsWith("Bearer ")) {
            sendErrorResponse(response, 401, "请先登录", "未提供有效的认证信息");
            return false;
        }

        // 获取到 token
        String accessToken = authorization.substring(7);
        try {
            // 验证token
            LoginServiceOuterClass.IntrospectRequest req = LoginServiceOuterClass.IntrospectRequest.newBuilder()
                    .setToken(accessToken)
                    .build();
            LoginServiceOuterClass.IntrospectReply introspection = loginServiceGrpc.introspect(req);

            if (!introspection.getActive()) {
                log.warn("token已失效: {}", accessToken);
                sendErrorResponse(response, 401, "登录已过期", "token已失效，请重新登录");
                return false;
            }

            String userId = introspection.getUserId();
            String username = introspection.getUsername();


            log.info("token验证成功: {}|{}|{}", accessToken, userId, username);
            // 设置用户信息
            UserContext.setUserDto(new UserDto(userId, username));
            return true;
        } catch (Exception e) {
            log.error("token验证异常: {}, {}", accessToken, e.getMessage(), e);
            sendErrorResponse(response, 401, "认证失败", "token验证失败，请重新登录");
            return false;
        }
    }


//    @Override
//    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
//        String traceId = StringUtils.defaultIfEmpty(request.getHeader(TRACE_ID), CommonUtils.getUuid());
//        CustomContext.setTraceId(traceId);
//        String authorization = request.getHeader("Authorization");
//        //拦截路径
//        String requestURI = request.getRequestURI();
//        log.info("TokenInterceptor拦截请求: {}", requestURI);
//        if (ObjectUtils.isEmpty(authorization) || authorization.length() < 8 || !authorization.startsWith("Bearer ")) {
//            response.setStatus(401);
//            response.setHeader("WWW-Authenticate", "Bearer realm=\"registered_users@xw-new-infra-window\"");
//            return false;
//        }
//        // 获取到 token
//        String accessToken = authorization.substring(7);
//        try {
//            // 验证token
//            LoginServiceOuterClass.IntrospectRequest req = LoginServiceOuterClass.IntrospectRequest.newBuilder()
//                    .setToken(accessToken)
//                    .build();
//            LoginServiceOuterClass.IntrospectReply introspection = loginServiceGrpc.introspect(req);
//            if (!introspection.getActive()) {
//                log.info("token fail:{}", accessToken);
//                response.setStatus(401);
//                response.setHeader("WWW-Authenticate", "invalid token");
//                return false;
//            }
//            log.info("token success: {}|{}|{}", accessToken, introspection.getUserId(), introspection.getUsername());
//            // 设置用户信息
//            UserContext.setUserDto(new UserDto(introspection.getUserId(), introspection.getUsername()));
//            return true;
//        } catch (Exception e) {
//            log.info("token exception: {}, {}", accessToken, e.toString(), e);
//            response.setStatus(402);
//            response.setHeader("WWW-Authenticate", "token validate failed");
//            return false;
//        }
//    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) {
        // Do nothing
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) {
        CustomContext.clear();
        UserContext.remove();
    }

    /**
     * 发送错误响应
     */
    private void sendErrorResponse(HttpServletResponse response, int status, String title, String message) throws IOException {
        response.setStatus(status);
        response.setContentType("application/json;charset=UTF-8");

        Map<String, Object> errorResponse = new HashMap<>();
        errorResponse.put("code", status);
        errorResponse.put("title", title);
        errorResponse.put("message", message);

        response.getWriter().write(objectMapper.writeValueAsString(errorResponse));
    }
}
